#-*- coding: utf-8 -*-

import logging
import lxml
import re
import sys
import urllib2

from django.conf import settings
from datetime import datetime
from datetime import date
from google.appengine.api import mail
from google.appengine.ext import db
from lxml.html import fromstring
from lxml.html.clean import Cleaner

class Encode:
    '''
    Helper class to remvoe encode method for unicode characters.
    Without this class, we need to do u'안녕하세요'.encode('utf-8')
    '''
    def __init__(self, stdout, enc):
        self.stdout = stdout
        self.encoding = enc

    def write(self, s):
        ''' Override stdout write'''
        if self.is_ascii(s):
            self.stdout.write(s.encode(self.encoding))
        else:
            self.stdout.write(s)

    def is_ascii(self, s):
        return all(ord(c) < 128 for c in s)


# Override standard output
sys.stdout = Encode(sys.stdout, 'utf-8')


#############################################################
#Starting django models to store data
##############################################################

class Account(db.Model):
    '''
    Account object to save the authenticated users
    '''

    # User object from the Google Auth system
    login = db.UserProperty()

    # First name of the Account holder
    first_name = db.StringProperty()

    # Last name of the Account holder
    last_name = db.StringProperty()

    # Status of the Account
    status = db.StringProperty()

    # Alternative email to get the notification
    primary_email = db.EmailProperty(required=False)

    # Create date of Account
    create_date = db.DateTimeProperty(auto_now_add=True)

    # Modify date of Account
    modify_date = db.DateTimeProperty(auto_now=True)


class TermStructure(db.Model):
    '''
    This model stores the term structure information for monitoring
    '''

    # Criteria to notify the user if it is not higher than a certain value
    # For example, users can set 5% and
    slope = db.FloatProperty()

    account = db.ReferenceProperty(Account,
                                   collection_name='term_structures')

    email_enabled = db.BooleanProperty(default=True, indexed=False)

    # Create date of Account
    create_date = db.DateTimeProperty(auto_now_add=True)

    # Modify date of Account
    modify_date = db.DateTimeProperty(auto_now=True)




###############################################################
#Finishing Django models
###############################################################


#################################################################
#Business Rules start here
#################################################################

class WebCrawler(object):
    """ Web content crawler to parse the watch item posting. """

    def __init__(self, url):
        self.url = url
        self.vix_data = dict()


    def fetch_vix_data(self):
        '''
        Fetch the data from vixcentral.com
        '''

        # Get the page source
        html = urllib2.urlopen(self.url).read().decode("latin1")

        # Run a regular expression to find the line of interest
        js_statement_regex_exp =  ".*last_data_var.*"
        last_data_line = \
          re.search(js_statement_regex_exp, html, re.M|re.I)

        # Parse the result line that was searched at the previous regex.
        if last_data_line:
            quote_regex_exp = ".*\[([0-9]*\.[0-9]*),\s([0-9]*\.[0-9]*).*"
            last_data_str = \
                re.search(quote_regex_exp, last_data_line.group(),re.M|re.I)
            return [float(last_data_str.group(1)),
                    float(last_data_str.group(2))]

    def is_vix_irregular(self, slope):
        '''
        Return a boolean value after calculating with a algorithm to
        see if the vix term structure looks ok.
        '''

        # Algorithm:
        # (one month maturity futures – current vix)/(current vix)
        # "as long as (one month maturity futures – current vix)/
        # (current vix) is greater than say, 5%, it is in a good shape.
        vix_data = self.fetch_vix_data()
        contango = (vix_data[1] - vix_data[0]) / vix_data[0]
        logging.info("Term Structure: (%s - %s)/%s = %s" %
                     (vix_data[1], vix_data[0], vix_data[0],
                      contango))

        # Cache the VIX data for the later use
        self.vix_data.update({"current_vix":vix_data[0]})
        self.vix_data.update({"one_month_vix":vix_data[1]})
        self.vix_data.update({"contango":contango})
        self.vix_data.update({"slope":slope})

        logging.info("Compare the contango %%:%s and slope: %s" % \
                      (contango, slope/100))
        return contango < (slope/100)


    def monitor_vix_data(self):
        '''
        Monitor if the conditions are met and send email if that is the case.
        '''

        q = TermStructure.all()

        for p in q.run():
            if self.is_vix_irregular(p.slope) and p.email_enabled:
                logging.info("Sending email to give a warning.")
                self.send_mail(p.account)
            else:
                logging.info("VIX has the regular term structure.")


    def send_mail(self, account):
        '''
        Function to send an email
        '''

        company_name = "Kiwishare"

        if account.first_name or account.last_name:
            receiver_name = "%s %s" % (account.first_name, account.last_name)
        else:
            receiver_name = account.primary_email

        message = mail.EmailMessage(
            sender=settings.MAIL_SENDER,
            subject="VIX Contango Notification")

        message.to = account.primary_email

        pretty_contango = '{:.2%}'.format(self.vix_data["contango"])

        logging.info("Contango percent %s" % pretty_contango)

        message.body = \
            ("Dear %s, \n\nWatch out the VIX Contango." +
          "\n\nContango: %s\nCurrent VIX: %s\nOne month future VIX: %s" +
          "\nContango Percent you provided for this warning: %s%%" +
          "\n\nYou may want to visit the site at http://www.vixcentral.com." +
          "\nAlso, you can go back to our site at " +
          settings.HOST_URL +
          "\n\n\nThanks, \n\n%s Team") % \
           (receiver_name,
            pretty_contango,
            self.vix_data["current_vix"],
            self.vix_data["one_month_vix"],
            self.vix_data["slope"],
            company_name)

        logging.info("Trying to send an email from %s to %s" % \
                     (settings.MAIL_SENDER, account.primary_email))
        message.send()
        logging.info("Sent the email to %s" % receiver_name)



